#include "expression.h"

namespace
{
	namespace qi = boost::spirit::qi;
	namespace ascii = boost::spirit::ascii;
	
	using ascii::digit;
	using ascii::alpha;
	using ascii::space;
	
	using qi::_val;
	using qi::_1;
	using qi::_2;
	using qi::phrase_parse;
	
	using std::string;
	using std::exception;
	
	template <typename Iterator>
	expression<Iterator>::expression() : expression<Iterator>::base_type(start)
	{
		number = (+digit)[_val = implementation::big_int_constructor()(_1)];
		function = +alpha;
		sum = 
			product[_val = _1] >> *(('+' >> product)[_val += _1] | 
			('-' >> product)[_val -= _1]);
		product = 
			power[_val = _1] >> *(('*' >> power)[_val *= _1]| 
			('/' >> power)[_val /= _1]);
		power = 
			expr[_val = _1] >> -('^' >> power)[_val = implementation::power()(_val, _1)];
		expr = 
			number[_val = _1] | 
			('-' >> expr)[_val = - _1] | 
			('(' >> sum >> ')')[_val = _1] | 
			(function >> '(' >> sum >> ')')[_val = implementation::function_()(_1, _2)];
		start %= sum > qi::eoi;
	}
	
	expression<string::const_iterator>& get_expression()
	{
		static expression<string::const_iterator> result;
		return result;
	}
}

big_int calculator(const string& s)
{
	big_int result;
	string::const_iterator begin = s.begin();
	string::const_iterator end = s.end();
	if (phrase_parse(begin, end, get_expression(), space, result))
		return result;
	else
		throw exception();
}
